﻿using RayD.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace RayD.Repository.Core
{
    /// <summary>
    /// 树型实体模型基类
    /// </summary>
    public class BaseTreeModel<T> where T : class
    {
        /// <summary>
        /// 节点id
        /// </summary>
        [NotMapped]
        public virtual string id { get; set; }
        /// <summary>
        /// 父节点Id
        /// </summary>
        [NotMapped]
        public virtual string parentId { get; set; }
        /// <summary>
        /// 节点值(选则的值)
        /// </summary>
        [NotMapped]
        public virtual string value { get; set; }
        /// <summary>
        /// 节点显示名
        /// </summary>
        [NotMapped]
        public virtual string label { get; set; }
        /// <summary>
        /// 节点图标
        /// </summary>
        [NotMapped]
        public virtual string icon { get; set; }

        /// <summary>
        /// 子节点数据
        /// </summary>
        [NotMapped]
        public IEnumerable<T> children { get; set; }
        /// <summary>
        /// 是否有子节点
        /// </summary>
        [NotMapped]
        public bool hasChildren { get; set; }
        /// <summary>
        /// 子节点是否已经加载完成了
        /// </summary>
        [NotMapped]
        public bool complete { get; set; }
        /// <summary>
        /// 是否为叶子节点( 懒加载有效 )
        /// </summary>
        [NotMapped]
        public virtual bool isLeaf { get { return this.parentId.IsEmpty() ? false : true; } }
    }

    /// <summary>
    /// List<BaseTreeModel> 的拓展类
    /// </summary>
    public static partial class Extention
    {
        /// <summary>
        /// 树形数据转化
        /// </summary>
        /// <param name="list">数据</param>
        /// <returns></returns>
        public static IEnumerable<T> ToTree<T>(this IEnumerable<T> list, string parentId = "") where T : BaseTreeModel<T>
        {
            Dictionary<string, List<T>> childrenMap = new Dictionary<string, List<T>>();
            Dictionary<string, T> parentMap = new Dictionary<string, T>();
            List<T> res = new List<T>();

            //首先按照
            foreach (var node in list)
            {
                node.hasChildren = false;
                node.complete = true;
                // 注册子节点映射表
                if (!childrenMap.ContainsKey(node.parentId))
                {
                    childrenMap.Add(node.parentId, new List<T>());
                }
                else if (parentMap.ContainsKey(node.parentId))
                {
                    parentMap[node.parentId].hasChildren = true;
                }
                childrenMap[node.parentId].Add(node);
                // 注册父节点映射节点表
                parentMap.Add(node.id, node);

                // 查找自己的子节点
                if (!childrenMap.ContainsKey(node.id))
                {
                    childrenMap.Add(node.id, new List<T>());
                }
                else
                {
                    node.hasChildren = true;
                }
                node.children = childrenMap[node.id];
            }
            if (string.IsNullOrEmpty(parentId))
            {
                // 获取祖先数据列表
                foreach (var item in childrenMap)
                {
                    if (!parentMap.ContainsKey(item.Key))
                    {
                        res.AddRange(item.Value);
                    }
                }
            }
            else
            {
                if (childrenMap.ContainsKey(parentId))
                {
                    return childrenMap[parentId];
                }
                else
                {
                    return new List<T>();
                }
            }
            return res;
        }
        /// <summary>
        /// 遍历树形数据获取全部子节点ID
        /// </summary>
        /// <param name="list">树形数据列表</param>
        /// <param name="outList">输出数据列表</param>
        public static void GetSubNodes<T>(this IEnumerable<T> list, List<string> outList) where T : BaseTreeModel<T>
        {
            foreach (var item in list)
            {
                outList.Add(item.id);
                if (item.hasChildren)
                {
                    GetSubNodes(item.children, outList);
                }
            }
        }

    }
}
